//===============================================================================
// Microsoft Architecture Strategy Team
// LitwareHR - SaaS Sample Application
//===============================================================================
// Copyright  Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Data;
using System.Data.Common;
using System.Data;

using Shp.Runtime.Contract;
using System.Data.SqlClient;
using System.Configuration;

namespace Shp.Runtime.Services
{
    static public class AuthorizationLogic
    {
        static public CredentialPermission[] GetCredentialPermissionList(string tenantAlias, string credential)
        {
            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TenantMetadataStore);

            List<CredentialPermission> list = new List<CredentialPermission>();

            using (DbCommand cmd = db.GetStoredProcCommand("dbo.GetCredentialPermissionList"))
            {
                db.AddInParameter(cmd, "tenantAlias", DbType.String, tenantAlias);
                db.AddInParameter(cmd, "credential", DbType.String, credential);

                using (IDataReader rdr = db.ExecuteReader(cmd))
                {
                    while (rdr.Read())
                    {
                        list.Add(PopulateCredentialPermissionFromIDataReader(rdr));
                    }
                }
            }

            return list.ToArray();
        }

        private static CredentialPermission PopulateCredentialPermissionFromIDataReader(IDataReader rdr)
        {
            CredentialPermission status = new CredentialPermission();

            status.ActionId = new Guid(rdr.GetValue(0).ToString());
            status.ActionUri = rdr.GetString(1);
            status.IsAuthorized = (rdr.GetValue(2) == DBNull.Value) ? false : true;
            status.Description = rdr.GetString(3);

            return status;
        }

        /// <summary>
        /// Updates the list of actions allowed for a credential.
        /// </summary>
        static public void UpdateCredentialPermission(string tenantAlias, string credential, Guid[] actionIdList)
        {
            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TenantMetadataStore);

            using (DbConnection conn = db.CreateConnection())
            {
                conn.Open();
                Guid tenantId = GetTenantIdByAlias(tenantAlias);

                string deleteCmdSql = "DELETE dbo.[Authorization] WHERE tenantId = @tenantId AND credential = @credential";
                using (DbCommand deleteCmd = db.GetSqlStringCommand(deleteCmdSql))
                {
                    db.AddInParameter(deleteCmd, "@tenantId", DbType.Guid, tenantId);
                    db.AddInParameter(deleteCmd, "@credential", DbType.String, credential);

                    deleteCmd.Connection = conn;
                    deleteCmd.ExecuteNonQuery();
                }

                string insertCmdSql = "INSERT INTO dbo.[Authorization] (id, actionId, tenantId, credential) VALUES (@ID, @ActionID, @TenantID, @Credential)";

                foreach (Guid actionID in new List<Guid>(actionIdList))
                {
                    DbCommand insertCmd = db.GetSqlStringCommand(insertCmdSql);

                    db.AddInParameter(insertCmd, "@ID", DbType.Guid, Guid.NewGuid());
                    db.AddInParameter(insertCmd, "@ActionID", DbType.Guid, actionID);
                    db.AddInParameter(insertCmd, "@TenantID", DbType.Guid, tenantId);
                    db.AddInParameter(insertCmd, "@Credential", DbType.String, credential);

                    insertCmd.Connection = conn;
                    insertCmd.ExecuteNonQuery();
                }
            }
        }

        static public string[] GetActions(string tenantAlias, string[] credentials)
        {
            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TenantMetadataStore);
            List<string> list = new List<string>();
            foreach (string credential in credentials)
            {
                using (DbCommand command = db.GetStoredProcCommand("dbo.GetActions"))
                {
                    db.AddInParameter(command, "tenantAlias", DbType.String, tenantAlias);
                    db.AddInParameter(command, "credential", DbType.String, credential);
                    using (IDataReader reader = db.ExecuteReader(command))
                    {
                        while (reader.Read())
                        {
                            if (!list.Contains(reader.GetString(0)))
                            {
                                list.Add(reader.GetString(0));
                            }
                        }
                    }
                }
            }
            return list.ToArray();
        }

        static public Guid GetTenantIdByAlias(string tenantAlias)
        {
            Database db = DatabaseFactory.CreateDatabase(Constants.DB.TenantMetadataStore);

            using (DbCommand command = db.GetStoredProcCommand("dbo.GetTenantIdByAlias"))
            {
                db.AddInParameter(command, "tenantAlias", DbType.String, tenantAlias);
                using (IDataReader reader = db.ExecuteReader(command))
                {
                    while (reader.Read())
                    {
                        return reader.GetGuid(0);
                    }
                }
            }

            throw new ArgumentException();
        }
    }
}
